package org.example.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Component;

import java.util.Comparator;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * TODO
 *
 * @Description
 * @Author ZW
 * @Date 2023/5/19 18:23
 **/
@Component
public class RedisUtil {
    RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private void init(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    //尝试上锁
    public boolean testLock(String wid,String uuid) {
        Boolean execute = redisTemplate.execute(new SessionCallback<Boolean>() {
            @Override
            public Boolean execute(RedisOperations operations) throws DataAccessException {
                operations.watch(wid);
                Object o = operations.opsForValue().get(wid);
                if (o != null)
                    return false;
                operations.multi();
                operations.opsForValue().set(wid,uuid,10000, TimeUnit.MILLISECONDS);
                List<Object> exec = operations.exec();
                if (exec.size() == 0)
                    return false;
                return true;
            }
        });
        return execute!=null && execute;
    }

    //基于函数式接口的上锁活动接口
    public <T> T lockAfterDo(String wid, String uuid, Supplier<T> tActivity) {
        T activity = null;
        try {
           if(testLock(wid, uuid)){
                activity = tActivity.get();
            }
       }finally {
           unLock(wid,uuid);
       }
        return activity;
    }
    public void unLock(String userId, String uuid) {
        //释放锁
         redisTemplate.execute(new SessionCallback<Void>() {
            @Override
            public Void execute(RedisOperations operations) throws DataAccessException {
                //监听这个值
                operations.watch(userId);
                //如果不是自己的锁就不能释放
                String o = (String) operations.opsForValue().get(userId);
                if (!uuid.equals(o))
                    return null;
                //开启任务队列
                operations.multi();
                //释放自己占用的锁
                operations.delete(userId);
                operations.exec();
                return null;
            }
        });
    }

    public <T> T key2Object(String key){
        return (T) redisTemplate.opsForValue().get(key);
    }
    public void set2Object(String key,Object obj){
         redisTemplate.opsForValue().set(key,obj);
    }

}